<template>
  <div class="message-container">
    <div
        v-for="msg in messages"
        :key="msg.id"
        class="el-message"
        :class="msg.type"
        :style="{
        top: calculateTop(msg),
        opacity: msg.closing ? 0 : 1,
        transform: msg.closing ? 'translateY(-20px)' : 'none',
        transition: 'opacity 0.3s ease, transform 0.3s ease'
      }"
        @mouseenter="pauseTimer(msg)"
        @mouseleave="resumeTimer(msg)"
        @click="msg.showClose ? remove(msg.id) : null"
    >
      <!-- 图标 -->
      <span class="el-message__icon" v-html="getIcon(msg.type)"></span>

      <!-- 文本 -->
      <span class="el-message__content">{{ msg.message }}</span>

      <!-- 关闭按钮 -->
      <span class="el-message__close" v-if="msg.showClose" @click.stop="remove(msg.id)">×</span>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { ref } from 'vue';

// 消息类型
type MessageType = 'success' | 'warning' | 'error' | 'info';

// 消息对象
interface MessageItem {
  id: number;
  message: string;
  type: MessageType;
  duration: number;
  showClose: boolean;
  onClose?: () => void;
  timer?: ReturnType<typeof setTimeout>;
  closing?: boolean; // 标记是否正在关闭
}

// 所有消息
const messages = ref<MessageItem[]>([]);

// 垂直间距（px）
const GAP = 16;
// 初始 top 位置
const TOP_OFFSET = 20;

// 计算每个消息的 top 位置（堆叠）
const calculateTop = (msg: MessageItem) => {
  const index = messages.value.findIndex(m => m.id === msg.id);
  return `${TOP_OFFSET + index * (GAP + 60)}px`; // 假设每条高 60px
};

// 图标映射
const getIcon = (type: MessageType) => {
  const icons: Record<MessageType, string> = {
    success: '✅',
    warning: '⚠️',
    error: '❌',
    info: 'ℹ️'
  };
  return icons[type];
};

// 添加消息
const add = (options: Partial<MessageItem>) => {
  const id = Date.now() + Math.random();

  const message: MessageItem = {
    id,
    message: options.message || '',
    type: options.type || 'info',
    duration: options.duration ?? 3000,
    showClose: options.showClose ?? false,
    onClose: options.onClose,
    timer: undefined,
    closing: false
  };

  messages.value.push(message);

  // 自动关闭
  if (message.duration > 0) {
    message.timer = setTimeout(() => {
      remove(id);
    }, message.duration);
  }

  return {
    close: () => remove(id)
  };
};

// 清除定时器（悬停时）
const pauseTimer = (msg: MessageItem) => {
  if (msg.timer) {
    clearTimeout(msg.timer);
    msg.timer = undefined;
  }
};

// 恢复定时器（离开时）
const resumeTimer = (msg: MessageItem) => {
  if (!msg.timer && msg.duration > 0) {
    msg.timer = setTimeout(() => {
      remove(msg.id);
    }, msg.duration);
  }
};

// 移除消息
const remove = (id: number) => {
  const index = messages.value.findIndex(msg => msg.id === id);
  if (index === -1) return;

  const msg = messages.value[index];
  msg.closing = true; // 触发关闭动画

  // 动画结束后真正移除
  setTimeout(() => {
    messages.value.splice(index, 1);
    if (msg.onClose) {
      msg.onClose();
    }
  }, 300); // 与 CSS transition 时间一致
};

// 导出调用方法
defineExpose({
  success(message: string, duration?: number, showClose: boolean = false) {
    return add({ message, type: 'success', duration, showClose });
  },
  error(message: string, duration?: number, showClose: boolean = false) {
    return add({ message, type: 'error', duration, showClose });
  },
  warning(message: string, duration?: number, showClose: boolean = false) {
    return add({ message, type: 'warning', duration, showClose });
  },
  info(message: string, duration?: number, showClose: boolean = false) {
    return add({ message, type: 'info', duration, showClose });
  },
  closeAll() {
    messages.value.forEach(msg => {
      if (msg.timer) clearTimeout(msg.timer);
      if (msg.onClose) msg.onClose();
    });
    messages.value = [];
  }
});
</script>

<style scoped>
.message-container {
  position: fixed;
  top: 0;
  right: 20px;
  z-index: 10000;
  max-width: 400px;
  width: 100%;
  pointer-events: none; /* 容器不拦截事件 */
}

.el-message {
  pointer-events: auto; /* 消息本身可交互 */
  width: 100%;
  min-height: 50px;
  margin-bottom: 16px;
  border-radius: 4px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  padding: 14px 20px;
  display: flex;
  align-items: center;
  background-color: #fff;
  box-sizing: border-box;
}

.el-message.success {
  background-color: #f0f9eb;
  color: #67c23a;
  border: 1px solid #e1f3d8;
}

.el-message.error {
  background-color: #fef0f0;
  color: #f56c6c;
  border: 1px solid #fde2e2;
}

.el-message.warning {
  background-color: #fdf6ec;
  color: #e6a23c;
  border: 1px solid #faecd8;
}

.el-message.info {
  background-color: #f4f4f5;
  color: #909399;
  border: 1px solid #e9e9eb;
}

.el-message__icon {
  margin-right: 10px;
  font-size: 18px;
}

.el-message__content {
  flex: 1;
  font-size: 14px;
}

.el-message__close {
  cursor: pointer;
  color: #c0c4cc;
  font-size: 16px;
  width: 18px;
  height: 18px;
  text-align: center;
  line-height: 18px;
  border-radius: 50%;
  background-color: #f2f2f2;
  margin-left: 8px;
}

.el-message__close:hover {
  color: #909399;
  background-color: #ebebeb;
}
</style>